﻿#include "TianJiaCS.h"
#include <stdio.h>
#include <time.h>
#include <map>
#include <QDebug>

#pragma execution_character_set("utf-8")

#pragma comment(lib,"ws2_32.lib")

#define MaxBufSize (1024*500)
//#define MaxSERVER  4
#define MaxClient (256*2)

//===========================================================
//helper Data

typedef struct _trans_data {
    const char* host;
    int port;
    SERVER_FUNC pConn;
    SERVER_FUNC pReceive;
    SERVER_FUNC pDisconn;
    LPVOID funParam;
    int sid;
    int cid;
} trans_data;

class ServerData {
public:

    ServerData(int i);
    ~ServerData();
    int clientNew();
    SOCKET* clientSocket(int cid);
    bool clientDelete(int cid);

    int sid;
    int lastcid;
    SOCKET* sock;
    map<int, SOCKET*> clientSock;
} ;
ServerData::ServerData(int i)
{
    sid=i;
    lastcid=0;
    sock=new SOCKET;
}

ServerData::~ServerData()
{
    auto iter = clientSock.begin();
    while(iter != clientSock.end()) {
        delete iter->second;
        iter++;
    }
    closesocket(*sock);
    delete sock;
}

int ServerData::clientNew()
{
    //连接数过多或开机过久
    if (lastcid >= MAXINT)return 0;
    ++lastcid;
    SOCKET *s=new SOCKET;
    clientSock[lastcid] = s;
    return lastcid;
}
SOCKET* ServerData::clientSocket(int cid)
{
    if(clientSock.find(cid)==clientSock.end()) return NULL;
    return clientSock[cid];
}
bool ServerData::clientDelete(int cid)
{
    SOCKET*p=clientSocket(cid);
    if(NULL==p) return false;
    closesocket(*p);
    delete p;
    return 1 == clientSock.erase(cid); //erase 删了返回1，没删返回0
}

//====================================================================================
//====================================================================================
int _tik=0;
map <int,ServerData*> servers;
map <int,HANDLE> threads;

//====================================================================================
DWORD WINAPI __ClientThread(LPVOID lpParameter);
DWORD WINAPI _ListenPort(LPVOID lpParameter);
//====================================================================================

//===========================================================
//
TianJiaCS:: TianJiaCS()
{
}

TianJiaCS::~TianJiaCS()
{
    auto iter = servers.begin();
    while(iter != servers.end()) {
        delete iter->second;
        iter++;
    }
}

int TianJiaCS::start(int port,
                       SERVER_FUNC onReceive,
                       SERVER_FUNC onConnected,
                       SERVER_FUNC onDisconnect,
                       void* funParam)
{
    _tik++;
    int sid=_tik;
    ServerData *da=new ServerData(sid);
    servers[sid]=da;

    trans_data *d=new trans_data;//由_ListenPort进程负责delete d;
    d->port = port;
    d->pConn = onConnected;
    d->pReceive = onReceive;
    d->pDisconn = onDisconnect;
    d->funParam = funParam;
    d->sid = sid;
    //printf("ServerStart port %d \n",port);
    CreateThread(NULL, 0, _ListenPort, d, 0, NULL);//由_ListenPort进程负责delete d;
    return sid;
}

void TianJiaCS::stop(int sid)
{
    //TerminateThread(hThread,EXIT_FAILURE);
    //CloseHandle(hThread);

    //TODO未结束的进程需要结束
    qDebug()<<"TianJiaCS::stop 1a "<<sid;
    ServerData *da=servers[sid];
    qDebug()<<"TianJiaCS::stop 1b "<<sid;
    WSACleanup();
    qDebug()<<"TianJiaCS::stop 1c "<<sid;
    servers.erase(sid);
    qDebug()<<"TianJiaCS::stop 1d "<<sid;
    delete da;
    qDebug()<<"TianJiaCS::stop 1e "<<sid;
}

bool TianJiaCS::sendMsg(int sid, int cid, const string& msg)
{
    ServerData *da=servers[sid];
    if(da->clientSock.find(cid)==da->clientSock.end()) return false;
    send(*da->clientSock[cid], msg.c_str(), (int)msg.size(), 0);
    return true;
}
bool TianJiaCS::sendMsgToAll(int sid, const string& msg)
{
    ServerData *da=servers[sid];
    auto iter = da->clientSock.begin();
    while(iter != da->clientSock.end()) {
        send(*iter->second, msg.c_str(), (int)msg.size(), 0);
        iter++;
    }
    return true;
}
//====================================================================================
// 1 监听线程：打开端口，并阻塞监听，等待客户端连接。
// 每个客户端连接进来后，均单独创建一个服务进程处理。
DWORD WINAPI _ListenPort(LPVOID lpParameter)
{
    trans_data *d0 = (trans_data*)lpParameter;
    int port = d0->port;
    SERVER_FUNC pConn = d0->pConn;
    SERVER_FUNC pReceive = d0->pReceive;
    SERVER_FUNC pDisconn = d0->pDisconn;
    LPVOID funParam = d0->funParam;
    int sid= d0->sid;
    SOCKET * pServSock = servers[sid]->sock;
    delete d0;

    WSAData wsd;
    WSAStartup(MAKEWORD(2, 2), &wsd);
    *pServSock = socket(AF_INET, SOCK_STREAM, 0);

    SOCKADDR_IN ListenAddr;
    ListenAddr.sin_family = AF_INET;
    ListenAddr.sin_addr.S_un.S_addr = INADDR_ANY;//表示填入本机ip
    ListenAddr.sin_port = htons(port);

    int n;
    int cid;
    n = ::bind(*pServSock, (LPSOCKADDR)&ListenAddr, sizeof(ListenAddr));
    if (n == SOCKET_ERROR) {
        //printf("bind err\n");// "端口绑定失败！"
        return -1;
    }
    int l = listen(*pServSock, 20);
    if(l<0){
        //printf("listen err\n");// "端口listen失败！"
        return -2;
    }
    //printf("JgAi/Server is Ready - listening at %d\n", port);

    while (1) {
        //循环接收客户端连接请求并创建服务线程
        cid = servers[sid]->clientNew();
        SOCKET *pClientSocket = servers[sid]->clientSocket(cid);
        *pClientSocket = accept(*pServSock, 0, 0);
        if(INVALID_SOCKET == *pClientSocket)break;
        trans_data *d2=new trans_data;
        d2->sid = sid;
        d2->cid = cid;
        d2->pConn=pConn;
        d2->pReceive=pReceive;
        d2->pDisconn=pDisconn;
        d2->funParam = funParam;

        //pClientSocket 和 d2 在 __ClientThread 里delete
        CreateThread(NULL, 0, __ClientThread, d2, 0, NULL);
    }//while 1

    return(0);
}
//====================================================================================
//2，服务线程： 创建无限循环，阻塞等待，处理SOCKET消息
DWORD WINAPI __ClientThread(LPVOID lpParameter) {
	trans_data *d2 = (trans_data*)lpParameter;
    int sid = d2->sid;
    int cid = d2->cid;
    SERVER_FUNC callbackConn = d2->pConn;
    SERVER_FUNC callbackReceive = d2->pReceive;
    SERVER_FUNC callbackDisconn = d2->pDisconn;
	LPVOID funParam = d2->funParam;
	delete d2;

    SOCKET *pClientSocket = servers[sid]->clientSocket(cid);
    if(pClientSocket==NULL)return -1;
    int receByt = 0,k;
    string answerMsg;

    char RecvBuf[MaxBufSize];

    //printf("New clinet #%lld\n", hc);
    if(callbackConn)
    {
        answerMsg.clear();
        callbackConn(cid, "", answerMsg, funParam);
        if(answerMsg.size()>0){
            k = send(*pClientSocket, answerMsg.c_str(),(int)answerMsg.size(), 0);
            if (k < 0) {
                //cout << "发送失败" << endl;
            }
        }
    }
    while (1) {
        receByt = recv(*pClientSocket, RecvBuf, sizeof(RecvBuf), 0);
		if (receByt >0) {
            RecvBuf[receByt] = 0;
            if (0 == strcmp(RecvBuf, "\n") || 0 == strcmp(RecvBuf, "\r")||
                0 == strcmp(RecvBuf, "\r\n") || 0 == strcmp(RecvBuf, "\n\r"))
            {
				continue;//空行忽略
            }
            answerMsg.clear();
            k=callbackReceive(cid,RecvBuf, answerMsg,funParam);
            if(answerMsg.size()>0){
                k = send(*pClientSocket, answerMsg.c_str(),(int)answerMsg.size(), 0);
				if (k < 0) {
					//cout << "发送失败" << endl;
				}
			}
		}
		else
        {
            /*if(callbackDisconn)
            {
                answerMsg.clear();
                callbackDisconn(cid, "", answerMsg, funParam);

                if(answerMsg.size()>0){
                    k = send(*pClientSocket, answerMsg.c_str(),(int)answerMsg.size(), 0);
                    if (k < 0) {
                        //cout << "发送失败" << endl;
                    }
                }
            }*/
            //printf("client %lld Exited.\n", hc);
			break;
		}
		//memset(RecvBuf, 0, sizeof(RecvBuf));
	}//while

    servers[sid]->clientDelete(cid);
	return 0;
}

